using System;
using System.Collections;
using System.Collections.Generic;
using Sirenix.OdinInspector;
using Survivor;
using UnityEngine;
using YDExtendTool.Scripts;

namespace DDA
{

    #region 控制语句
    public abstract class DDAControlFlow : DDATreeNodeBase
    {
        public override void OnConnected(TreeNodeBase node)
        {
            base.OnConnected(node);
            this._nodes.Sort((n1,n2)=>(int)(n1.Position.y-n2.Position.y));
        }
    }
    
    public class DDAStart : DDAControlFlow
    {
        public override int NextNodeMaxNum => 1;

        [ShowInInspector, LabelText("是否自动间隔触发")]
        public bool isAutoInvoke = true;

        [ShowInInspector, LabelText("触发间隔"), ShowIf("isAutoInvoke")]
        public float interval;

        [ShowInInspector,ReadOnly]
        public bool isStart = false;
        [ShowInInspector,ReadOnly]
        public bool isEnd = false;
        public Action OnEnd;

        public override bool Invoke()
        {
            base.Invoke();
            // 自动间隔触发的时候，如果再被invoke直接返回
            if (isAutoInvoke && isStart)
            {

                return isEnd;
            }
            
            // 非自动间隔触发的时候，但是执行完成了，被invoke直接返回
            if (isEnd)
            {
                 #if  UNITY_EDITOR
                    ResetState(this);
                #endif
                return isEnd;
            }
            

            if (isAutoInvoke)
            {
                DDAParser.Instance.StartCoroutine(IStart());
                return false;
            }
            else
            {
                if (ChildNodes[0] is { } ddaTreeNodeBase)
                {
                    #if UNITY_EDITOR
                    ResetState(ChildNodes[0]);
                    #endif
                    isEnd = ddaTreeNodeBase.Invoke();
                    if (isEnd)
                    {
                        OnEnd?.Invoke();
                    }

                    return isEnd;
                }
            }
            // if (ChildNodes.Count == 0) return true;
            // if (ChildNodes[0] is DDATreeNodeBase ddaTreeNodeBase)
            // {
            //     return ddaTreeNodeBase.Invoke();
            // }

            return true;
        }


        private IEnumerator IStart()
        {
            isStart = true;
            if (ChildNodes.Count != 0)
            {
                var waitSec = new WaitForSeconds(interval);
                var result = false;
                while (!result)
                {
                    if (ChildNodes[0] is { } ddaTreeNodeBase)
                    {
                        #if UNITY_EDITOR
                        ResetState(ChildNodes[0]);
                        #endif
                        result = ddaTreeNodeBase.Invoke();
                        
                    }

                    if (Mathf.Approximately(interval, 0f))
                    {
                        yield return null;
                    }
                    else
                    {
                        yield return waitSec;
                    }
                }
            }

#if  UNITY_EDITOR
            ResetState(this);
#endif
            isEnd = true;
            OnEnd?.Invoke();
        }

        public void ResetState(DDATreeNodeBase node)
        {
            node.state = DDATreeNodeState.Disable;
            foreach (var childNode in node.ChildNodes)
            {
                ResetState(childNode);
            }
        }

        public override void Reset()
        {
            base.Reset();
            OnEnd = null;
            isStart = false;
            isEnd = false;
        }
    }

    public class DDASelect : DDAControlFlow
    {
        public override int NextNodeMaxNum => 10;

        public override bool Invoke()
        {
            base.Invoke();
            var result = false;
            foreach (var t in ChildNodes)
            {
                if (t is { } ddaTreeNodeBase)
                {
                    result |= ddaTreeNodeBase.Invoke();
                    if (result) return true;
                }
            }
            return false;
        }

    }

    public class DDASequence : DDAControlFlow
    {
        public override int NextNodeMaxNum => 10;
        [ShowInInspector] public bool IsLoop { get; set; } = true;
        [ShowInInspector, ReadOnly] private int _index = 0;

        public override bool Invoke()
        {
            base.Invoke();
            if (_index >= ChildNodes.Count)
            {
                if (IsLoop) _index = 0;
                return true;
            }

            if (ChildNodes[_index] is { } ddaTreeNodeBase)
            {
                var result = ddaTreeNodeBase.Invoke();
                if (result) _index += 1;
            }

            return false;
        }

        public override void Reset()
        {
            base.Reset();
            _index = 0;
        }
    }

    public class DDAIfElse : DDAControlFlow
    {
        public override int NextNodeMaxNum => 3;

        public override bool Invoke()
        {      
            base.Invoke();
            if (ChildNodes.Count < 2)
            {
#if UNITY_EDITOR
                Debug.LogWarning("DDAIfElse节点不能小于2个");
#endif
                return true;
            }

            if (ChildNodes[0] is { } condition)
            {
                if (condition.Invoke())
                {
                    if (ChildNodes[1] is { } action)
                    {
                        if (action.Invoke())
                        {
                            return true;
                        }
                    }
                }
                else
                {
                    if (ChildNodes.Count >= 3 && ChildNodes[2] is { } action)
                    {
                        if (action.Invoke())
                        {
                            return true;
                        }
                    }
                }
            }

            return false;
        }
    }

    public class DDAWhile : DDAControlFlow,IOutputObject
    {
        public override int NextNodeMaxNum => 10;
        [ShowInInspector, LabelText("开始")] public int start = 0;
        [ShowInInspector,LabelText("结束")] public int end = 0;
        [ShowInInspector, ReadOnly,LabelText("执行次数")] public int _num = 0;
        [ShowInInspector, ReadOnly, LabelText("当前下标")] public int Index =>start +_num;
        public override bool Invoke()
        {
            base.Invoke();
            if (Index+start >= end)
            {
                _num = 0;
                return true;
            }
            if (ChildNodes.Count > 0)
            {
                for (int i = 0; i < ChildNodes.Count; i++)
                {
                    if (ChildNodes[i] is { } ddaTreeNodeBase)
                    {
                        if (ddaTreeNodeBase is IInputObject inputObject)
                        {
                            inputObject.ReceiveObject(OutputObject());
                        }

                        ddaTreeNodeBase.Invoke();
                    }
                }
                                        
                _num+=1;
            }

            return false;
        }

        public override void Reset()
        {
            base.Reset();
            _num = 0;
        }

        public Type OutputType()
        {
            return typeof(int);
        }

        public object OutputObject()
        {
            return Index;
        }
    }

    public class DDAWhileImmediately : DDAWhile
    {
        [ShowInInspector, LabelText("是否要求遍历全部成功"), Tooltip("为否的时候，遍历过程中，出现一次全部子节点为true就返回true")]
        public bool isForceAllSuccess = false;

        public override string Description => "DDAWhileImmediately: 一次调用，输出end-star次，每次输出int，表示当前index(index∈[start,end))";

        public override bool Invoke()
        {
            this.state = DDATreeNodeState.Enable;
            var result = isForceAllSuccess;
            if (ChildNodes.Count > 0)
            {
                for (int i = 0; i < end-start; i++)
                {
                    this._num = i;
                    var t_result = true;
                    for (int j = 0; j < ChildNodes.Count; j++)
                    {
                        if (ChildNodes[j] is { } ddaTreeNodeBase)
                        {
                            if (ddaTreeNodeBase is IInputObject inputObject)
                            {
                                inputObject.ReceiveObject(OutputObject());
                            }
                            
                            t_result &= ddaTreeNodeBase.Invoke();
                        }
                    }

                    if (isForceAllSuccess)
                    {
                        result &= t_result;
                    }
                    else
                    {
                        result |= t_result;
                    }
                }
            }

            return result;
        }
    }

    public class DDAAll : DDAControlFlow
    {
        public override int NextNodeMaxNum => 10;

        public override bool Invoke()
        {
            base.Invoke();
            var result = true;
            for (int i = 0; i < ChildNodes.Count; i++)
            {
                result &= ChildNodes[i].Invoke();
            }

            return result;
        }
    }

    public class DDAOnceAll : DDAControlFlow
    {
        public override int NextNodeMaxNum => 10;
        private bool isHasInvoke = false;

        public override bool Invoke()
        {
            base.Invoke();
            if (isHasInvoke) return true;
            isHasInvoke = true;
            // 不关心结果
            for (int i = 0; i < ChildNodes.Count; i++)
            {
                if (ChildNodes[i] is { } ddaTreeNodeBase)
                {
                    ddaTreeNodeBase.Invoke();
                }
            }

            return base.Invoke();
        }

        public override void Reset()
        {
            isHasInvoke = false;
            base.Reset();
        }
    }

    public class DDADoOnce : DDAControlFlow
    {
        public override int NextNodeMaxNum => 1;
        private bool isHasInvoke = false;

        [ShowInInspector, LabelText("是否在意子节点执行结果"),Tooltip("为true时，只有子节点成功执行，才认为已经执行了一次。为false则无论后续节点是否成功执行，都不会再执行第二次")]
        public bool isChildrenInvokeResult = false;

        public override bool Invoke()
        {
            base.Invoke();
            if (isHasInvoke) return true;
            if (ChildNodes.Count != 0)
            {
                var result = ChildNodes[0].Invoke();
                isHasInvoke = !isChildrenInvokeResult | result;
                return isHasInvoke;
            }

            return true;
        }

        public override void Reset()
        {
            base.Reset();
            isHasInvoke = false;
        }
    }


    #endregion
    
    #region 输入输出
    
    #region 输入输出基类
    interface IInputObject
    {
        Type InputType();
        void ReceiveObject(object obj);
    }
    interface IOutputObject
    {
        Type OutputType();
        object OutputObject();
    }
    
    /// <summary>
    /// 简单的输入输出节点,能够右端输出结果, 不能接受数据
    /// </summary>
    public abstract class DDAOutputObject : DDATreeNodeBase, IOutputObject
    {
        public override int NextNodeMaxNum => 10;

        [ShowInInspector, LabelText("是否只赋值不调用"), Tooltip("为true则会赋值且invoke子节点，false则只赋值")]
        public virtual bool IsOnlySendValueToChildren { get; set; } = false;

        public override bool CanConnect(TreeNodeBase treeNodeBase)
        {
            return base.CanConnect(treeNodeBase) && treeNodeBase is IInputObject input &&
                   (input.InputType()==OutputType() || OutputType() == typeof(object));
        }
        
        public override bool Invoke()
        {
            base.Invoke();
            var result = true;
            for (int i = 0; i < ChildNodes.Count; i++)
            {
                var input = ChildNodes[i] as IInputObject;
                if (input != null)
                {
                    input.ReceiveObject(OutputObject());
                    if (!IsOnlySendValueToChildren) result &= ChildNodes[i].Invoke();
                    if (!result) return false;
                }
                else
                {
                    Debug.LogWarning("DDAOutputObject 的子节点必须实现IInputObject");
                }
            }

            return result;
        }

        public abstract Type OutputType();

        public abstract object OutputObject();
    }
    
    /// <summary>
    /// 支持左右端输出结果
    /// </summary>
    public abstract class DDAOutputAndGet: DDAOutputObject,IGetValue
    {
        public object GetValue()
        {
            return OutputObject();
        }
    }
    
    /// <summary>
    /// 支持输入和右端输出
    /// </summary>
    public abstract class DDAInputAndOutput:  DDAOutputObject,IInputObject
    {
        public abstract Type InputType();

        public abstract void ReceiveObject(object obj);
    }

    /// <summary>
    /// 数据区，能够双端输出数据，并且能够接受输入
    /// </summary>
    public abstract class DDAData:DDAOutputAndGet,IInputObject
    {
        public abstract Type InputType();

        public abstract void ReceiveObject(object obj);
    }

    public class DDAConvert : DDAInputAndOutput
    {
        [ShowInInspector, LabelText("输入类型")] public Type inputType;
        [ShowInInspector, LabelText("目标类型")] public Type outputType;
        [ShowInInspector,ReadOnly] private object value;
        public override Type OutputType()
        {
            return outputType;
        }

        public override object OutputObject()
        {
            return Convert.ChangeType(value,outputType);
        }

        public override Type InputType()
        {
            return inputType;
        }

        public override void ReceiveObject(object obj)
        {
            this.value = obj;
        }
    }
    
    /// <summary>
    /// </summary>
    public class DDAInputAndOutputWithoutInvoke: DDAInputAndOutput
    {
        public override string NodeName => "赋值过渡节点";
        public override string Description => "只赋值，不调用子节点Invoke方法";
        public override bool IsOnlySendValueToChildren => true;

        public override bool Invoke()
        {
            return base.Invoke();
        }

        [ShowInInspector,ReadOnly] private object value;
        public override Type OutputType()
        {
            return typeof(object);
        }

        public override object OutputObject()
        {
            return value;
        }

        public override Type InputType()
        {
            return typeof(object);
        }

        public override void ReceiveObject(object obj)
        {
            this.value = obj;
        }
    }
    
    #endregion



    public class DDAOutputGameTime : DDAOutputObject
    {

        public override Type OutputType()
        {
            return typeof(float);
        }

        public override object OutputObject()
        {
            return Global.CurrentTime.Value;
        }
    }

    public class DDAOutputNumber : DDAOutputObject
    {
        public override int NextNodeMaxNum => 10;
        [ShowInInspector,LabelText("数值")] public float value = 0;
        public override Type OutputType()
        {
            return typeof(float);
        }

        public override object OutputObject()
        {
            return value;
        }
    }


    public class DDAStep : DDAOutputObject
    {
        public override int NextNodeMaxNum => 10;
        
        [FoldoutGroup("函数"), ShowInInspector, LabelText("初始X")]
        public int initX = 0;

        [FoldoutGroup("函数"), ShowInInspector, LabelText("步长"),]
        public float step = 1;

        [FoldoutGroup("函数"), ShowInInspector, LabelText("结束")]
        public float end = 1;

        private float _curX = 0;

        public override void Reset()
        {
            base.Reset();
            _curX = 0;
        }

        public override Type OutputType()
        {
            return typeof(float);
        }

        public override object OutputObject()
        {
            if (_curX == 0) _curX = initX;
            var value = _curX;
            _curX += step;
            return value;
        }
    }
    
    public class DDAGetValue : DDAAction, IGetValue,IInputObject
    {
        [ShowInInspector, LabelText("值类型")] public virtual Type type { get; set; }
        [ShowInInspector] public object value = 0;
        public override string Description => "DDAGetValue: 能够接受指定类型的数据并存储，以及左输出存储的数据";

        public virtual object GetValue()
        {
            return value;
        }

        public Type InputType()
        {
            return type;
        }

        public void ReceiveObject(object obj)
        {
            this.value = obj;
        }
    }

    public class DDAGetFloat : DDAGetValue
    {
        public override Type type => typeof(float);

        public override object GetValue()
        {
            return (float)value;
        }
    }


    public class DDAGetPlayerHealthRate : DDAOutputAndGet
    {
        public override Type OutputType()
        {
            return typeof(float);
        }

        public override object OutputObject()
        {
            Debug.Log("DDAGetPlayerHealthRate："+ 1.0f*Global.Hp.Value/Global.MaxHp.Value);
            return 1.0f*Global.Hp.Value/Global.MaxHp.Value;
        }
    }

    public class DDAGetPlayerLevel : DDAOutputAndGet
    {
        public override Type OutputType()
        {
            return typeof(int);
        }

        public override object OutputObject()
        {
            return Global.Level.Value;
        }
    }
    
    public class DDAGetEnemyCount : DDAOutputAndGet
    {
        public override Type OutputType()
        {
            return typeof(int);
        }

        public override object OutputObject()
        {
            return EnemyGenerator.EnemyNum.Value;
        }
    }


    public class DDAGetAbilityLevel:DDAData
    {
        [ShowInInspector, LabelText("能力")] public AbilityEnum abilityEnum;
        #if UNITY_EDITOR
        public override string Description => "DDAGetAbilityLevel: 获得当前能力的等级，能够接受一个int变量，表示对应的能力。";
        #endif
        [ShowInInspector, LabelText("等级"),ReadOnly] public int level = 0;
        public override string NodeName => abilityEnum switch
        {
            AbilityEnum.SimpleAttack => "获得普通攻击等级",
            AbilityEnum.SimpleAxe => "获得斧头攻击等级",
            AbilityEnum.SimpleCircle => "获得环绕攻击等级",
            AbilityEnum.SimpleKnife => "获得小刀攻击等级",
            AbilityEnum.Critical=>"获得暴击率等级",
            AbilityEnum.Damage=>"获得伤害等级",
            AbilityEnum.FlyThingCount=>"获得发射物书数量等级",
            AbilityEnum.MoveSpeed => "获得移动速度等级",
            AbilityEnum.PickUpRange => "获得拾取范围等级",
            AbilityEnum.Exp => "获得经验等级",
            _ => ""
        };
    
        public override Type OutputType()
        {
            return typeof(int);
        }

        public override object OutputObject()
        {
            var system = Global.Interface.GetSystem<ExpUpgradeSystem>();
            if (system != null && system.items.Count>0)
            {
                level = system.items[(int)abilityEnum].Level;
                return level;
            }

            return 0;
        }

        public override Type InputType()
        {
            return typeof(int);
        }

        public override void ReceiveObject(object obj)
        {
            this.abilityEnum =(AbilityEnum)obj;
        }
    }
    #endregion
    

    #region 函数
    public abstract class DDAFunciton : DDAInputAndOutput
    {
        public override int NextNodeMaxNum => 10;
        public abstract float Function(float x);
        [ShowInInspector, LabelText("函数表达式")] public virtual string FunctionExpression { get; }

        [ShowInInspector, ReadOnly,LabelText("输入的值")] private float inputValue;
        public override string NodeName => FunctionExpression;
        

        public override Type InputType()
        {
            return typeof(float);
        }

        public override Type OutputType()
        {
            return typeof(float);
        }

        public override object OutputObject()
        {
            return Function(this.inputValue);
        }

        public override void ReceiveObject(object obj)
        {
            this.inputValue = (float)obj;
        }
    }

    /// <summary>
    /// 线性函数
    /// </summary>
    public class DDALinearFunciton : DDAFunciton
    {
        public override int NextNodeMaxNum => 10;
        public override string FunctionExpression => $"y = {k}*x+{b}";
        [ShowInInspector] public float k = 0;
        [ShowInInspector] public float b = 0;

        public override float Function(float x)
        {
            return k * x + b;
        }
    }

    public class DDACeilLinearFunction : DDALinearFunciton
    {
        public override string FunctionExpression => $"y = {a} * ceil({k}*x)+{b}";
        [ShowInInspector] public float a = 1;

        public override float Function(float x)
        {
            return a * Mathf.Ceil(k * x) + b;
        }
    }

    public class DDAAbsFunciton : DDAFunciton
    {
        public override string FunctionExpression => "y = abs(x)";

        public override float Function(float x)
        {
            return Mathf.Abs(x);
        }
    }

    public class DDASinFunciton : DDAFunciton
    {
        public override string FunctionExpression => "y = a*sin(w*x+b*π)+c";
        public int a;
        public int w;
        public int b;
        public int c;
        
        public override float Function(float x)
        {
            return a * Mathf.Sin(w * x + b * Mathf.PI) + c;
        }
    }

    public class DDACosFunciton : DDAFunciton
    {
        public override string FunctionExpression => "y = a*cos(w*x+b*π)+c";
        public int a;
        public int w;
        public int b;
        public int c;
        
        public override float Function(float x)
        {
            return a * Mathf.Cos(w * x + b * Mathf.PI) + c;
        }
    }
    
    public class DDATanFunciton : DDAFunciton
    {
        public override string FunctionExpression => "y = a*tan(w*x+b*π)+c";
        public int a;
        public int w;
        public int b;
        public int c;
        
        public override float Function(float x)
        {
            return a * Mathf.Tan(w * x + b * Mathf.PI) + c;
        }
    }

    public class DDAClampFunction : DDAFunciton
    {
        public override string FunctionExpression => "y = clamp(x,min,max)";
        [ShowInInspector,LabelText("最小值")] public int min;
        [ShowInInspector,LabelText("最大值")] public int max;
        public override float Function(float x)
        {
            return Mathf.Clamp(x,min,max);
        }
    }

    public class DDASimplePiecewiseFunction : DDAFunciton
    {
        public override string FunctionExpression => "简单分段函数";

        public struct Interval
        {
            public float min;
            public float max;
            public float value;

            public bool IsInInterval(float x)
            {
                return x >= min && x < max;
            }
        }

        [ShowInInspector,LabelText("区间"),Tooltip("区间判定：min<=x<max，输入值时会遍历该数组,找到第一个位于的区间")] 
        public List<Interval> intervals = new List<Interval>();
        
        
        public override float Function(float x)
        {
            for (int i = 0; i < intervals.Count; i++)
            {
                if (intervals[i].IsInInterval(x))
                {
                    return intervals[i].value;
                }
            }

            return 0;
        }
    }


    #endregion 

}